package com.demo.aspect;

import com.demo.annotation.DataSource;
import com.demo.dataSource.DynamicDataSourceHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 配置数据源的切面
 */
@Order(1)
@Aspect
@Component
public class DataSourceAspect {

    @Pointcut("execution(* com.demo.service.impl.*.*(..))")
    public void pointcut(){
    }


    /**
     * 拦截目标方法,获取由@DataSource指定的数据源标识, 设置到线程存储中以便切换数据源
     * @param point
     */
    @Before("pointcut()")
    public void  intercept(JoinPoint point){
        //先清除原来的数据源
        DynamicDataSourceHolder.clearDataSource();
        Class target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        //默认使用目标类型的注解, 如果没有则使用其实现接口的注解
        for (Class clazz: target.getInterfaces()) {
            resolveDataSource(clazz,signature.getMethod());
        }
        resolveDataSource(target,signature.getMethod());
    }

    /**
     * 提取目标对象方法注解和类注解中的数据源标识
     * @param clazz
     * @param method
     */
    private void resolveDataSource(Class clazz, Method method) {
        Class<?>[] types = method.getParameterTypes();
        //默认使用类注解
        if(clazz.isAnnotationPresent(DataSource.class)){
            DataSource dataSource = (DataSource) clazz.getAnnotation(DataSource.class);
            DynamicDataSourceHolder.setDataSource(dataSource.value());
        }
        //方法注解覆盖类注解
        try {
            Method m = clazz.getMethod(method.getName(), types);
            if(m != null && m.isAnnotationPresent(DataSource.class)){
                DataSource dataSource = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(dataSource.value());
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 错误 :
 * 总结 :
 */